#include <linux/clocksource.h>
#include <linux/list.h>
#include <linux/timekeeping.h>
#include <linux/limits.h>
#include <linux/time.h>
#include <linux/math.h>

static LIST_HEAD(clocksource_list);

static void clocksource_enqueue(struct clocksource *cs)
{
    struct list_head *entry = &clocksource_list;

    list_add(&cs->list, entry);
}

static void clocksource_select(void)
{
    struct clocksource *best = NULL, *cs;

    list_for_each_entry(cs, &clocksource_list, list)
    {
        best = cs;
    }

    if (best)
    {
        timekeeping_notify(best);
    }
}

/**
 * clocksource_update_max_deferment - Updates the clocksource max_idle_ns & max_cycles
 * @cs:         Pointer to clocksource to be updated
 *
 */
static inline void clocksource_update_max_deferment(struct clocksource *cs)
{
    cs->max_idle_ns = clocks_calc_max_nsecs(cs->mult, cs->shift,
                                            cs->maxadj, cs->mask,
                                            &cs->max_cycles);

    /*
     * Threshold for detecting negative motion in clocksource_delta().
     *
     * Allow for 0.875 of the counter width so that overly long idle
     * sleeps, which go slightly over mask/2, do not trigger the
     * negative motion detection.
     */
    cs->max_raw_delta = (cs->mask >> 1) + (cs->mask >> 2) + (cs->mask >> 3);
}

/**
 * __clocksource_update_freq_scale - Used update clocksource with new freq
 * @cs:		clocksource to be registered
 * @scale:	Scale factor multiplied against freq to get clocksource hz
 * @freq:	clocksource frequency (cycles per second) divided by scale
 *
 * This should only be called from the clocksource->enable() method.
 *
 * This *SHOULD NOT* be called directly! Please use the
 * __clocksource_update_freq_hz() or __clocksource_update_freq_khz() helper
 * functions.
 */
void __clocksource_update_freq_scale(struct clocksource *cs, u32 scale, u32 freq)
{
    u64 sec;

    /*
     * Default clocksources are *special* and self-define their mult/shift.
     * But, you're not special, so you should specify a freq value.
     */
    if (freq)
    {
        /*
         * Calc the maximum number of seconds which we can run before
         * wrapping around. For clocksources which have a mask > 32-bit
         * we need to limit the max sleep time to have a good
         * conversion precision. 10 minutes is still a reasonable
         * amount. That results in a shift value of 24 for a
         * clocksource with mask >= 40-bit and f >= 4GHz. That maps to
         * ~ 0.06ppm granularity for NTP.
         */
        sec = cs->mask;
        do_div(sec, freq);
        do_div(sec, scale);
        if (!sec)
            sec = 1;
        else if (sec > 600 && cs->mask > UINT_MAX)
            sec = 600;

        clocks_calc_mult_shift(&cs->mult, &cs->shift, freq,
                               NSEC_PER_SEC / scale, sec * scale);
    }

    clocksource_update_max_deferment(cs);
}

static void clocksource_enqueue_watchdog(struct clocksource *cs)
{
    if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS)
        cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
}

/**
 * __clocksource_register_scale - Used to install new clocksources
 * @cs:		clocksource to be registered
 * @scale:	Scale factor multiplied against freq to get clocksource hz
 * @freq:	clocksource frequency (cycles per second) divided by scale
 *
 * Returns -EBUSY if registration fails, zero otherwise.
 *
 * This *SHOULD NOT* be called directly! Please use the
 * clocksource_register_hz() or clocksource_register_khz helper functions.
 */
static int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
{
    __clocksource_update_freq_scale(cs, scale, freq);

    clocksource_enqueue(cs);
    clocksource_enqueue_watchdog(cs);

    clocksource_select();

    return 0;
}

int clocksource_register_hz(struct clocksource *cs, unsigned int hz)
{
    return __clocksource_register_scale(cs, 1, hz);
}
